package com.dynabook.ems.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dynabook.ems.common.BaseResponse;
import com.dynabook.ems.common.ErrorCode;
import com.dynabook.ems.common.ResultUtils;
import com.dynabook.ems.constant.MailTemplate;
import com.dynabook.ems.exception.BusinessException;
import com.dynabook.ems.mapper.EmsEngineWorkOrderMapper;
import com.dynabook.ems.mapper.EmsMainEngineMapper;
import com.dynabook.ems.mapper.EmsMyBorrowMapper;
import com.dynabook.ems.mapper.EmsWorkOrderMapper;
import com.dynabook.ems.model.bo.ChangeMachineBO;
import com.dynabook.ems.model.bo.OldMachineMessageBO;
import com.dynabook.ems.model.bo.OldModificationBO;
import com.dynabook.ems.model.dto.*;
import com.dynabook.ems.model.dto.request.WorkOrderBatchAcceptanceRequest;
import com.dynabook.ems.model.dto.request.WorkOrderBatchApprovalRequest;
import com.dynabook.ems.model.dto.request.WorkOrderBatchDeleteRequest;
import com.dynabook.ems.model.dto.request.WorkOrderBatchRejectRequest;
import com.dynabook.ems.model.entity.*;
import com.dynabook.ems.model.enums.*;
import com.dynabook.ems.model.vo.*;
import com.dynabook.ems.service.*;
import com.dynabook.ems.utils.FastExcelUtils;
import com.dynabook.ems.utils.SampleStatusUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 工单服务实现类
 */
@Service
@Slf4j
public class EmsWorkOrderServiceImpl extends ServiceImpl<EmsWorkOrderMapper, EmsWorkOrder> implements EmsWorkOrderService {
    
    @Resource
    private EmsBomService emsBomService;

    @Resource
    private EmsEngineWorkOrderMapper emsEngineWorkOrderMapper;
    @Resource
    private EmsMyBorrowMapper emsMyBorrowMapper;
    
    @Resource
    private EmsMainEngineMapper emsMainEngineMapper;

    @Resource
    private EmsMyBorrowService emsMyBorrowService;

    @Resource
    private EmsMainEngineService emsMainEngineService;

    @Resource
    private RedisTemplate redisTemplate;
    
    @Resource
    private EmsLogRecordService emsLogRecordService;
    
    @Resource
    private RolesService rolesService;

    @Resource
    private WorkOrderStatusSyncService workOrderStatusSyncService;
    @Resource
    private EmsWorkOrderDetailService emsWorkOrderDetailService;
    @Resource
    private EmsEngineWorkOrderService emsEngineWorkOrderService;
    @Resource
    private EmsBomContactService emsBomContactService;

    @Resource
    private MailTemplate mailTemplate;

    @Resource
    private UsersService usersService;

    @Resource
    private EmsMailQueueService emsMailQueueService;

    @Resource
    private EmsProductionRecordsService emsProductionRecordsService;

    @Resource
    private SampleStatusUtils sampleStatusUtils;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public BaseResponse<Boolean> addWorkOrder(WorkOrderAddRequest request, HttpServletRequest httpServletRequest) {
         String workOrderNum = request.getWorkOrderNum();
         String finishedProductModel = request.getFinishedProductModel();
         String version = request.getVersion();
         Integer productionQuantity = request.getProductionQuantity();

        try {
            // 1. 参数验证
            if (request == null) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "请求参数不能为空");
            }
            if (StrUtil.isBlank(workOrderNum)) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "工单号不能为空");
            }
            if (StrUtil.isBlank(finishedProductModel)) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "成品型号不能为空");
            }
            if (StrUtil.isBlank(version)) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "版本号不能为空");
            }
            if (productionQuantity == null || productionQuantity <= 0) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "生产数量必须大于0");
            }
    
            // 2. 获取用户信息
            UserLoginVO userLoginVO = (UserLoginVO) httpServletRequest.getSession().getAttribute("user_login");
            if (userLoginVO == null) {
                throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR, "用户未登录");
            }
    
            // 3. 检查工单号是否已存在
//            LambdaQueryWrapper<EmsWorkOrder> workOrderWrapper = new LambdaQueryWrapper<>();
//            workOrderWrapper.eq(EmsWorkOrder::getWorkOrderNum, workOrderNum)
//                           .eq(EmsWorkOrder::getIsDelete, 0);
//            EmsWorkOrder existingWorkOrder = this.getOne(workOrderWrapper);
//            if (existingWorkOrder != null) {
//                throw new BusinessException(ErrorCode.PARAMS_ERROR, "工单号已存在: " + workOrderNum);
//            }
    
//            // 4. 校验该工单下所有BOM详情状态必须为已选状态
            LambdaQueryWrapper<EmsWorkOrderDetail> detailWrapper = new LambdaQueryWrapper<>();
            detailWrapper.eq(EmsWorkOrderDetail::getWorkOrderNumber, workOrderNum)
                        .eq(EmsWorkOrderDetail::getIsDelete, 0);
            List<EmsWorkOrderDetail> bomDetails = emsWorkOrderDetailService.list(detailWrapper);

            if (bomDetails.isEmpty()) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "该工单下没有关联的样品详情");
            }

//             检查是否所有详情状态都是已选状态或者是改造品
            boolean allSelected = bomDetails.stream()
                    .allMatch(detail -> DetailStatusEnum.SELECTED.getValue().equals(detail.getDetailStatus())
                            || DetailStatusEnum.MODIFICATION.getValue().equals(detail.getDetailStatus()));

            if (!allSelected) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "样品状态没有全部为已选");
            }
            Optional<EmsWorkOrderDetail> firstDetail = bomDetails.stream()
                    .filter(detail -> detail.getIsFirst() == 1)
                    .findFirst();

            // 处理成品名称逻辑
            if (firstDetail.isPresent()) {
                EmsWorkOrderDetail detail = firstDetail.get();
                String modelType = detail.getModelType();
                
                if (StrUtil.isNotBlank(modelType)) {
                    // 根据modelType查询ems_main_engine表
                    LambdaQueryWrapper<EmsMainEngine> mainEngineWrapper = new LambdaQueryWrapper<>();
                    mainEngineWrapper.eq(EmsMainEngine::getType, modelType)
                            .last("LIMIT 1");
                    EmsMainEngine mainEngine = emsMainEngineMapper.selectOne(mainEngineWrapper);
                    
                    if (mainEngine != null) {
                        String bigCategory = mainEngine.getBigCategory();
                        String finishedProductName;
                        
                        // 根据bigCategory确定成品名称
                        if ("Machine".equals(bigCategory)) {
                            finishedProductName = "笔记本电脑";
                        } else if ("PCBA".equals(bigCategory)) {
                            finishedProductName = "主板";
                        } else {
                            finishedProductName = "其他";
                        }
                        
                        // 存储到Redis
                        String redisKey = workOrderNum + ":finished_product_name";
                        redisTemplate.opsForValue().set(redisKey, finishedProductName);
                        log.info("成功存储成品名称到Redis: key={}, value={}", redisKey, finishedProductName);
                    } else {
                        log.warn("未找到匹配的样品信息，型号: {}", modelType);
                    }
                } else {
                    log.warn("工单详情中的型号为空，工单号: {}", workOrderNum);
                }
            } else {
                log.warn("未找到第一条工单详情记录，工单号: {}", workOrderNum);
            }

            // 5. 根据成品型号和版本查询BOM信息
            LambdaQueryWrapper<EmsBom> bomWrapper = new LambdaQueryWrapper<>();
            bomWrapper.eq(EmsBom::getFinishedProductModel, finishedProductModel)
                     .eq(EmsBom::getVersion, version)
                     .eq(EmsBom::getIsDelete, 0);
            EmsBom bomInfo = emsBomService.getOne(bomWrapper);
            if (bomInfo == null) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, 
                    "未找到对应的BOM信息，成品型号: " +finishedProductModel + ", 版本: " + version);
            }
    
            // 6. 创建工单实体
            EmsWorkOrder workOrder = new EmsWorkOrder();
            workOrder.setWorkOrderNum(workOrderNum);
            workOrder.setProductionQuantity(productionQuantity);
            workOrder.setBomId(bomInfo.getId());
            workOrder.setUserId(userLoginVO.getUserNum());
            workOrder.setUserName(userLoginVO.getUserName());
            workOrder.setWorkOrderStatus(WorkOrderStatusEnum.PENDING.getValue()); // 初始状态为待处理
            workOrder.setUpdateTime(LocalDateTime.now());
            workOrder.setIsDelete(0);
    
            // 7. 保存工单
            boolean saveResult = this.saveOrUpdate(workOrder);
            if (!saveResult) {
                throw new BusinessException(ErrorCode.SYSTEM_ERROR, "保存工单失败");
            }
//          TODO 新建工单邮件 完成
            ArrayList<HashMap<String, String>> tableDatas = new ArrayList<>();
            HashMap<String, String> tableDataMap= new HashMap<String, String>();
            tableDataMap.put("workOrderNum",workOrderNum);
            tableDataMap.put("name",finishedProductModel);
            tableDataMap.put("bomNum", bomInfo.getBomNum());
            tableDataMap.put("bomVersion","V"+bomInfo.getVersion());
            tableDatas.add(tableDataMap);
            //  样机管理员拒绝发邮件
            EmsMailQueue emsMailQueue = new EmsMailQueue();
            emsMailQueue.setType(MailEnum.WORK_ORDER_APPROVAL.getValue());
            emsMailQueue.setMainBody(mailTemplate.getWorkOrderApproval());
            emsMailQueue.setSubject(MailTemplate.SUBJECT_WORK_ORDER_APPROVAL+" "+userLoginVO.getSectionName()+" "+userLoginVO.getUserName());
            emsMailQueue.setFrom(userLoginVO.getEmail());
            List<String> sectionMails = usersService.getSectionMails(userLoginVO.getSectionId());
            emsMailQueue.setTo(sectionMails.toString());
            emsMailQueue.setTableData(tableDataMap.toString());
            boolean saveMail = emsMailQueueService.save(emsMailQueue);
            if (!saveMail) {
                throw new BusinessException(ErrorCode.SYSTEM_ERROR, "保存邮件失败");
            }
            log.info("成功创建工单，工单号: {}, 用户: {}", workOrderNum, userLoginVO.getUserName());
            return ResultUtils.success(true);
    
        } catch (BusinessException e) {
            log.error("创建工单失败: {}", e.getMessage());
            throw e;
        } catch (Exception e) {
            log.error("创建工单时发生异常", e);
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "创建工单失败"+ e.getMessage());
        }
    }

    @Override
    public Page<WorkOrderListVO> getWorkOrderList(WorkOrderListRequest workOrderListRequest) {
        log.info("查询工单列表，参数: {}", workOrderListRequest);
        
        // 参数校验
        if (workOrderListRequest == null) {
            workOrderListRequest = new WorkOrderListRequest();
        }
        
        // 设置默认排序
        if (StrUtil.isBlank(workOrderListRequest.getSortField())) {
            workOrderListRequest.setSortField("insert_time");
            workOrderListRequest.setSortOrder("desc");
        }
        
        // 创建分页对象
        Page<WorkOrderListVO> page = new Page<>(workOrderListRequest.getCurrent(), workOrderListRequest.getPageSize());
        
        // 执行分页查询
        return this.baseMapper.pageWorkOrderList(page, workOrderListRequest);
    }
    
    @Override
    public Page<WorkOrderApprovalListVO> getWorkOrderApprovalList(WorkOrderApprovalListRequest workOrderApprovalListRequest) {
        log.info("查询工单审批列表，参数: {}", workOrderApprovalListRequest);
        
        // 参数校验
        if (workOrderApprovalListRequest == null) {
            workOrderApprovalListRequest = new WorkOrderApprovalListRequest();
        }
        
        // 设置默认排序
        if (StrUtil.isBlank(workOrderApprovalListRequest.getSortField())) {
            workOrderApprovalListRequest.setSortField("insert_time");
            workOrderApprovalListRequest.setSortOrder("desc");
        }
        
        // 创建分页对象
        Page<WorkOrderApprovalListVO> page = new Page<>(workOrderApprovalListRequest.getCurrent(), workOrderApprovalListRequest.getPageSize());
        
        // 执行分页查询
        return this.baseMapper.pageWorkOrderApprovalList(page, workOrderApprovalListRequest);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public BaseResponse<Boolean> batchProcessWorkOrders(WorkOrderBatchRejectRequest request, HttpServletRequest httpServletRequest) {
        log.info("批量处理工单申请，参数: {}", request);
        
        try {
            // 1. 参数验证
            if (request == null || request.getWorkOrderIds() == null || request.getWorkOrderIds().isEmpty()) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "工单ID列表不能为空");
            }
            
            if (StrUtil.isBlank(request.getActionType())) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "操作类型不能为空");
            }
            
            // 2. 查询工单列表

            List<EmsWorkOrder> workOrders = this.listByIds(request.getWorkOrderIds());
            if (workOrders.isEmpty()) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "未找到对应的工单信息");
            }
            
            // 3. 验证工单状态，只有待生产审批状态的工单才能处理
            List<EmsWorkOrder> invalidWorkOrders = workOrders.stream()
                    .filter(workOrder -> !WorkOrderStatusEnum.PENDING.getValue().equals(workOrder.getWorkOrderStatus()))
                    .collect(Collectors.toList());
            
            if (!invalidWorkOrders.isEmpty()) {
                String invalidWorkOrderNums = invalidWorkOrders.stream()
                        .map(EmsWorkOrder::getWorkOrderNum)
                        .collect(Collectors.joining(", "));
                throw new BusinessException(ErrorCode.PARAMS_ERROR, 
                        "以下工单状态不是待生产审批，无法处理: " + invalidWorkOrderNums);
            }
            
            // 4. 根据操作类型执行不同逻辑
            if ("reject".equals(request.getActionType())) {
                // 拒绝逻辑：更新工单状态为待修改
                processRejectWorkOrders(workOrders, request.getRejectReason(), httpServletRequest,request.getWorkOrderIds());
            } else if ("agree".equals(request.getActionType())) {
                // 同意逻辑：更新工单状态为备货中，并处理借用记录
                processAgreeWorkOrders(workOrders, httpServletRequest,request.getWorkOrderIds());
            } else {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "不支持的操作类型: " + request.getActionType());
            }
            
            String workOrderNums = workOrders.stream()
                    .map(EmsWorkOrder::getWorkOrderNum)
                    .collect(Collectors.joining(", "));
            log.info("成功批量{}工单: {}", "agree".equals(request.getActionType()) ? "同意" : "拒绝", workOrderNums);
            
            return ResultUtils.success(true);
            
        } catch (BusinessException e) {
            log.error("批量处理工单失败: {}", e.getMessage());
            throw e;
        } catch (Exception e) {
            log.error("批量处理工单时发生异常", e);
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "批量处理工单失败");
        }
    }
    
    /**
     * 处理拒绝工单逻辑
     */
    private void processRejectWorkOrders(List<EmsWorkOrder> workOrders, String rejectReason, HttpServletRequest httpServletRequest,List<String> workOrderIds) {
        // 收集所有工单号，用于批量查询
        List<String> workOrderNums = workOrders.stream()
                .map(EmsWorkOrder::getWorkOrderNum)
                .collect(Collectors.toList());
        
        // 批量查询所有工单关联的样品信息
        LambdaQueryWrapper<EmsEngineWorkOrder> engineWrapper = new LambdaQueryWrapper<>();
        engineWrapper.in(EmsEngineWorkOrder::getWorkOrderNumber, workOrderNums)
                    .eq(EmsEngineWorkOrder::getIsDelete, 0);
        List<EmsEngineWorkOrder> allEngineWorkOrders = emsEngineWorkOrderMapper.selectList(engineWrapper);
        
        // 按工单号分组
        Map<String, List<EmsEngineWorkOrder>> workOrderEngineMap = allEngineWorkOrders.stream()
                .collect(Collectors.groupingBy(EmsEngineWorkOrder::getWorkOrderNumber));
        
        // 用于批量操作的集合
        List<EmsLogRecord> logRecordsToInsert = new ArrayList<>();
        
        for (EmsWorkOrder workOrder : workOrders) {
            workOrder.setWorkOrderStatus(WorkOrderStatusEnum.MODIFIED.getValue());
            workOrder.setUpdateTime(LocalDateTime.now());
            // 如果有拒绝原因，可以设置到备注字段
            if (StrUtil.isNotBlank(rejectReason)) {
                workOrder.setReason(rejectReason);
            }
            
            // 为该工单关联的每个样品创建拒绝日志记录
            List<EmsEngineWorkOrder> engineWorkOrders = workOrderEngineMap.get(workOrder.getWorkOrderNum());
            if (engineWorkOrders != null && !engineWorkOrders.isEmpty()) {
                for (EmsEngineWorkOrder engineWorkOrder : engineWorkOrders) {
                    try {
                        // 获取用户角色信息
                        UserRoleVO userRole = rolesService.getRoleByUserId(workOrder.getUserId());
                        String roleNotes = (userRole != null && userRole.getNotes() != null) ? userRole.getNotes() : "";
                        
                        EmsLogRecord logRecord = new EmsLogRecord();
                        logRecord.setFixedNo(engineWorkOrder.getFixedNo());
                        logRecord.setDesc("工单审批");
                        logRecord.setRole(roleNotes);
                        logRecord.setOperator(workOrder.getUserName());
                        logRecord.setType("审批");
                        logRecord.setResult("拒绝");
                        logRecord.setTime(LocalDateTime.now());
                        logRecordsToInsert.add(logRecord);
                    } catch (Exception e) {
                        log.warn("获取用户角色信息失败，用户ID: {}, 错误: {}", workOrder.getUserId(), e.getMessage());
                        // 即使获取角色信息失败，也要插入日志记录，只是role字段为空
                        EmsLogRecord logRecord = new EmsLogRecord();
                        logRecord.setFixedNo(engineWorkOrder.getFixedNo());
                        logRecord.setDesc("工单审批");
                        logRecord.setRole("");
                        logRecord.setOperator(workOrder.getUserName());
                        logRecord.setType("审批");
                        logRecord.setResult("拒绝");
                        logRecord.setTime(LocalDateTime.now());
                        logRecordsToInsert.add(logRecord);
                    }
                }
            }
        }
    
        // 批量插入拒绝日志记录
        if (!logRecordsToInsert.isEmpty()) {
            boolean insertLogResult = emsLogRecordService.saveBatch(logRecordsToInsert);
            if (!insertLogResult) {
                throw new BusinessException(ErrorCode.SYSTEM_ERROR, "批量插入拒绝日志记录失败");
            }
            log.info("成功批量插入 {} 条拒绝日志记录", logRecordsToInsert.size());
        }
        
        // TODO 发送工单拒绝邮件完成
        sendBatchRejectEmail(workOrders, rejectReason, httpServletRequest,workOrderIds);

        // 执行批量更新
        boolean updateResult = this.updateBatchById(workOrders);
        if (!updateResult) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "批量更新工单状态失败");
        }
    }
    
    /**
     * 处理同意工单逻辑
     */
    private void processAgreeWorkOrders(List<EmsWorkOrder> workOrders, HttpServletRequest httpServletRequest,List<String> workOrderIds) {
        // 收集所有工单号，用于批量查询
        List<String> workOrderNums = workOrders.stream()
                .map(EmsWorkOrder::getWorkOrderNum)
                .collect(Collectors.toList());
        
        // 批量查询所有工单关联的样品信息
        LambdaQueryWrapper<EmsEngineWorkOrder> engineWrapper = new LambdaQueryWrapper<>();
        engineWrapper.in(EmsEngineWorkOrder::getWorkOrderNumber, workOrderNums)
                    .eq(EmsEngineWorkOrder::getIsDelete, 0);
        List<EmsEngineWorkOrder> allEngineWorkOrders = emsEngineWorkOrderMapper.selectList(engineWrapper);
        
        if (allEngineWorkOrders.isEmpty()) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "未找到工单关联的样品信息");
        }
        
        // 过滤逻辑：剔除allEngineWorkOrders中emsRequestId不为空且在ems_my_borrow表中is_delete=0的数据
        if (CollUtil.isNotEmpty(allEngineWorkOrders)) {
            // 收集所有不为空的emsRequestId
            List<String> emsRequestIds = allEngineWorkOrders.stream()
                    .filter(order -> StrUtil.isNotBlank(order.getEmsRequestId()))
                    .map(EmsEngineWorkOrder::getEmsRequestId)
                    .distinct()
                    .collect(Collectors.toList());
            
            // 查询ems_my_borrow表中is_delete=0的记录
            if (CollUtil.isNotEmpty(emsRequestIds)) {
                LambdaQueryWrapper<EmsMyBorrow> borrowWrapper = new LambdaQueryWrapper<>();
                borrowWrapper.in(EmsMyBorrow::getEmsRequestId, emsRequestIds)
                        .eq(EmsMyBorrow::getIsDelete, 0);
                List<EmsMyBorrow> borrowList = emsMyBorrowMapper.selectList(borrowWrapper);
                
                // 收集需要剔除的emsRequestId
                if (CollUtil.isNotEmpty(borrowList)) {
                    Set<String> excludeRequestIds = borrowList.stream()
                            .map(EmsMyBorrow::getEmsRequestId)
                            .collect(Collectors.toSet());
                    
                    // 从allEngineWorkOrders中剔除这些数据
                    allEngineWorkOrders = allEngineWorkOrders.stream()
                            .filter(order -> StrUtil.isBlank(order.getEmsRequestId()) 
                                    || !excludeRequestIds.contains(order.getEmsRequestId()))
                            .collect(Collectors.toList());
                }
            }
        }
        
        // 按工单号分组
        Map<String, List<EmsEngineWorkOrder>> workOrderEngineMap = allEngineWorkOrders.stream()
                .collect(Collectors.groupingBy(EmsEngineWorkOrder::getWorkOrderNumber));
        
        // 收集所有样品编号，用于批量查询样品信息
        List<String> allFixedNos = allEngineWorkOrders.stream()
                .map(EmsEngineWorkOrder::getFixedNo)
                .distinct()
                .collect(Collectors.toList());
        
        // 批量查询所有样品信息
        LambdaQueryWrapper<EmsMainEngine> mainEngineWrapper = new LambdaQueryWrapper<>();
        mainEngineWrapper.in(EmsMainEngine::getFixedNo, allFixedNos);
        List<EmsMainEngine> allMainEngines = emsMainEngineMapper.selectList(mainEngineWrapper);
        
        // 转换为Map便于查找
        Map<String, EmsMainEngine> mainEngineMap = allMainEngines.stream()
                .collect(Collectors.toMap(EmsMainEngine::getFixedNo, Function.identity()));
        
        // 用于批量操作的集合
        List<EmsMyBorrow> borrowsToInsert = new ArrayList<>();
        List<EmsMainEngine> enginesToUpdate = new ArrayList<>();
        List<EmsEngineWorkOrder> engineWorkOrdersToUpdate = new ArrayList<>();
        List<EmsLogRecord> logRecordsToInsert = new ArrayList<>();
        
        // 处理每个工单
        // 获取起始的requestId
        String baseRequestId = emsMyBorrowMapper.getRequestNo();
        // 解析出当前的序号
        String yearMonth = baseRequestId.substring(1, 5); // 提取年月部分
        int currentSequence = Integer.parseInt(baseRequestId.substring(5)); // 提取序号部分
        
        int sequenceCounter = 0; // 用于递增序号
        
        for (EmsWorkOrder workOrder : workOrders) {
            List<EmsEngineWorkOrder> engineWorkOrders = workOrderEngineMap.get(workOrder.getWorkOrderNum());
            
            if (engineWorkOrders == null || engineWorkOrders.isEmpty()) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, 
                        "工单 " + workOrder.getWorkOrderNum() + " 未找到关联的样品信息");
            }
            
            // 验证库存并准备数据
            for (EmsEngineWorkOrder engineWorkOrder : engineWorkOrders) {
                // 手动生成递增的requestId
                int nextSequence = currentSequence + sequenceCounter;
                String requestId = String.format("R%s%04d", yearMonth, nextSequence);
                sequenceCounter++; // 为下一条记录递增
                
                EmsMainEngine mainEngine = mainEngineMap.get(engineWorkOrder.getFixedNo());
                
                if (mainEngine == null) {
                    throw new BusinessException(ErrorCode.PARAMS_ERROR, 
                            "样品编号 " + engineWorkOrder.getFixedNo() + " 不存在");
                }
                EmsMyBorrow myBorrow = new EmsMyBorrow();
                EmsMainEngine engineToUpdate = new EmsMainEngine();
                // 检查库存是否充足
                Integer inventoryNum = mainEngine.getInventoryNum() != null ? mainEngine.getInventoryNum() : 0;
                Integer usedNum = mainEngine.getUsedNum() != null ? mainEngine.getUsedNum() : 0;
                Integer borrowNum = engineWorkOrder.getBorrowNum() != null ? engineWorkOrder.getBorrowNum() : 0;
                if(engineWorkOrder.getIsMy()==1){
                    myBorrow.setRequestStatus(ModelStatusEnum.USING.getValue());
                    workOrderStatusSyncService.onRequestStatusChange(requestId, ModelStatusEnum.USING.getValue());
                    myBorrow.setIsWorkOrder(2);
                    engineToUpdate.setUsedNum(usedNum - borrowNum);
                }else{
                    if (borrowNum > inventoryNum) {
                        throw new BusinessException(ErrorCode.PARAMS_ERROR,
                                String.format("样品编号 %s 库存不足，当前库存: %d，需求数量: %d",
                                        engineWorkOrder.getFixedNo(), inventoryNum, borrowNum));
                    }
                    myBorrow.setRequestStatus(ModelStatusEnum.WORK_ORDER_ASSIGNING.getValue());
                    myBorrow.setIsWorkOrder(1);
                    engineToUpdate.setInventoryNum(inventoryNum - borrowNum);
                    engineToUpdate.setModelStatus(ModelStatusEnum.WORK_ORDER_ASSIGNING.getValue());
                }
                // 准备借用记录
                myBorrow.setEmsRequestId(requestId); // 使用手动生成的唯一requestId
                myBorrow.setFixedNo(engineWorkOrder.getFixedNo());
                myBorrow.setBorrowNum(engineWorkOrder.getBorrowNum());
                myBorrow.setUserName(workOrder.getUserName());
                myBorrow.setUserId(workOrder.getUserId());
                myBorrow.setBorrowTime(new Date());
                myBorrow.setInsertTime(LocalDateTime.now());
                myBorrow.setUpdateTime(LocalDateTime.now());
                myBorrow.setIsDelete(0);
                borrowsToInsert.add(myBorrow);
                // 准备样品库存更新
                Integer currentScrapNum = mainEngine.getScrapNum() != null ? mainEngine.getScrapNum() : 0;
                engineToUpdate.setUserName(workOrder.getUserName());
                engineToUpdate.setUserId(workOrder.getUserId());
                engineToUpdate.setFixedNo(mainEngine.getFixedNo());
                engineToUpdate.setScrapNum(currentScrapNum + borrowNum);
                engineToUpdate.setUpdateTime(LocalDateTime.now());
                enginesToUpdate.add(engineToUpdate);

                // 准备更新 ems_engine_work_order 表的 ems_request_id
                EmsEngineWorkOrder engineWorkOrderToUpdate = new EmsEngineWorkOrder();
                engineWorkOrderToUpdate.setFixedNo(engineWorkOrder.getFixedNo());
                engineWorkOrderToUpdate.setWorkOrderNumber(engineWorkOrder.getWorkOrderNumber());
                engineWorkOrderToUpdate.setDetailId(engineWorkOrder.getDetailId());
                engineWorkOrderToUpdate.setEmsRequestId(requestId);
                engineWorkOrderToUpdate.setUpdateTime(LocalDateTime.now());
                engineWorkOrdersToUpdate.add(engineWorkOrderToUpdate);

                log.info("库存验证通过，样品编号: {}, 当前库存: {}, 需求数量: {}, 请求ID: {}",
                        engineWorkOrder.getFixedNo(), inventoryNum, borrowNum, requestId);
                // 准备日志记录
                try {
                    // 获取用户角色信息
                    UserRoleVO userRole = rolesService.getRoleByUserId(workOrder.getUserId());
                    String roleNotes = (userRole != null && userRole.getNotes() != null) ? userRole.getNotes() : "";
                    
                    EmsLogRecord logRecord = new EmsLogRecord();
                    logRecord.setFixedNo(engineWorkOrder.getFixedNo());
                    logRecord.setDesc("工单申请");
                    logRecord.setRole(roleNotes);
                    logRecord.setOperator(workOrder.getUserName());
                    logRecord.setType("申请");
                    logRecord.setTime(LocalDateTime.now());
                    logRecordsToInsert.add(logRecord);
                } catch (Exception e) {
                    log.warn("获取用户角色信息失败，用户ID: {}, 错误: {}", workOrder.getUserId(), e.getMessage());
                    // 即使获取角色信息失败，也要插入日志记录，只是role字段为空
                    EmsLogRecord logRecord = new EmsLogRecord();
                    logRecord.setFixedNo(engineWorkOrder.getFixedNo());
                    logRecord.setDesc("工单申请");
                    logRecord.setRole("");
                    logRecord.setOperator(workOrder.getUserName());
                    logRecord.setType("申请");
                    logRecord.setTime(LocalDateTime.now());
                    logRecordsToInsert.add(logRecord);
                }
                

            }
            
            // 更新工单状态
            workOrder.setWorkOrderStatus(WorkOrderStatusEnum.INSTOCK.getValue());
            workOrder.setUpdateTime(LocalDateTime.now());
            
            // 将样品信息存储到Redis Hash中
            try {
                String redisKey = RedisKeyEnum.WORKER_ORDER_APPROVAL_PREFIX.getValue() + workOrder.getWorkOrderNum();
                for (EmsEngineWorkOrder engineWorkOrder : engineWorkOrders) {
                    redisTemplate.opsForHash().put(redisKey, engineWorkOrder.getFixedNo(), 0);
                }
                log.info("成功将工单样品信息存储到Redis，工单号: {}, 样品数量: {}", 
                        workOrder.getWorkOrderNum(), engineWorkOrders.size());
            } catch (Exception e) {
                log.error("Redis存储工单审批信息失败，工单号: {}, 错误: {}", workOrder.getWorkOrderNum(), e.getMessage(), e);
                // Redis操作失败不影响主流程，只记录日志
            }
        }
        
        // 批量执行数据库操作
        try {
            // 1. 批量插入借用记录
            if (!borrowsToInsert.isEmpty()) {
                boolean insertResult = emsMyBorrowService.saveBatch(borrowsToInsert);
                if (!insertResult) {
                    throw new BusinessException(ErrorCode.SYSTEM_ERROR, "批量插入借用记录失败");
                }
                log.info("成功批量插入 {} 条借用记录", borrowsToInsert.size());
            }
            
            // 2. 批量插入日志记录
            if (!logRecordsToInsert.isEmpty()) {
                boolean insertLogResult = emsLogRecordService.saveBatch(logRecordsToInsert);
                if (!insertLogResult) {
                    throw new BusinessException(ErrorCode.SYSTEM_ERROR, "批量插入日志记录失败");
                }
                log.info("成功批量插入 {} 条日志记录", logRecordsToInsert.size());
            }
            
            // 3. 批量更新样品库存
            if (!enginesToUpdate.isEmpty()) {
                boolean updateEngineResult = emsMainEngineService.updateBatchById(enginesToUpdate);
                if (!updateEngineResult) {
                    throw new BusinessException(ErrorCode.SYSTEM_ERROR, "批量更新样品库存失败");
                }
                log.info("成功批量更新 {} 条样品库存记录", enginesToUpdate.size());
            }
            
            // 4. 批量更新 ems_engine_work_order 表的 ems_request_id
            if (!engineWorkOrdersToUpdate.isEmpty()) {
                for (EmsEngineWorkOrder engineWorkOrder : engineWorkOrdersToUpdate) {
                    LambdaUpdateWrapper<EmsEngineWorkOrder> updateWrapper = new LambdaUpdateWrapper<>();
                    updateWrapper.eq(EmsEngineWorkOrder::getFixedNo, engineWorkOrder.getFixedNo())
                           .eq(EmsEngineWorkOrder::getWorkOrderNumber, engineWorkOrder.getWorkOrderNumber())
                           .eq(EmsEngineWorkOrder::getDetailId, engineWorkOrder.getDetailId())
                           .set(EmsEngineWorkOrder::getEmsRequestId, engineWorkOrder.getEmsRequestId())
                           .set(EmsEngineWorkOrder::getUpdateTime, engineWorkOrder.getUpdateTime());
                    emsEngineWorkOrderMapper.update(null, updateWrapper);
                }
                log.info("成功批量更新 {} 条工单样品关联记录的请求ID", engineWorkOrdersToUpdate.size());
            }
            
            // 5. 批量更新工单状态
            boolean updateWorkOrderResult = this.updateBatchById(workOrders);
            if (!updateWorkOrderResult) {
                throw new BusinessException(ErrorCode.SYSTEM_ERROR, "批量更新工单状态失败");
            }
            log.info("成功批量更新 {} 条工单状态", workOrders.size());
            
        } catch (Exception e) {
            log.error("批量操作失败: {}", e.getMessage(), e);
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "批量操作失败: " + e.getMessage());
        }
        
        // TODO 发送工单同意邮件完成
        sendBatchApproveEmail(workOrders, httpServletRequest, workOrderIds);
    }

    /**
     * PM完工 - 优化版本
     * @param request 批量审批请求
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public BaseResponse<Boolean> batchApprovalInProductionWorkOrders(WorkOrderBatchApprovalRequest request, HttpServletRequest httpServletRequest) {
        log.info("批量审批生产中工单，参数: {}", request);

        try {
            List<String> workOrderNums = request.getWorkOrderNums();

            // 查询所有工单的当前状态
            LambdaQueryWrapper<EmsWorkOrder> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.in(EmsWorkOrder::getWorkOrderNum, workOrderNums)
                    .eq(EmsWorkOrder::getIsDelete, 0);
            List<EmsWorkOrder> workOrders = this.list(queryWrapper);

            if (workOrders.size() != workOrderNums.size()) {
                return ResultUtils.error(ErrorCode.PARAMS_ERROR, "部分工单不存在或已删除");
            }

            // 检查所有工单状态是否都是生产中(状态值为3)
            List<EmsWorkOrder> nonInProductionOrders = workOrders.stream()
                    .filter(order -> !WorkOrderStatusEnum.INPRODUCTION.getValue().equals(order.getWorkOrderStatus()))
                    .collect(Collectors.toList());

            if (!nonInProductionOrders.isEmpty()) {
                List<String> nonInProductionNums = nonInProductionOrders.stream()
                        .map(EmsWorkOrder::getWorkOrderNum)
                        .collect(Collectors.toList());
                return ResultUtils.error(ErrorCode.PARAMS_ERROR,
                        "有工单状态为非生产中的状态，工单号: " + String.join(", ", nonInProductionNums));
            }

            // 批量更新工单状态为待验收(状态值为4)
            LambdaUpdateWrapper<EmsWorkOrder> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.in(EmsWorkOrder::getWorkOrderNum, workOrderNums)
                    .eq(EmsWorkOrder::getIsDelete, 0)
                    .set(EmsWorkOrder::getWorkOrderStatus, WorkOrderStatusEnum.ACCEPT.getValue())
                    .set(EmsWorkOrder::getUpdateTime, LocalDateTime.now());

            boolean updateResult = this.update(updateWrapper);
            
            // 处理改造品和成品信息 - 使用优化后的方法
            processModificationAndFinishedProducts(workOrderNums, workOrders);
//            workOrders
            List<String> workOrderNumbers = workOrders.stream().map(EmsWorkOrder::getWorkOrderNum).collect(Collectors.toList());
            if(CollUtil.isNotEmpty(workOrderNumbers)){
                List<EmsProductionRecords> emsProductionRecords = this.baseMapper.getEmsProductionRecordMessage(workOrderNumbers);
                boolean saveBatch = emsProductionRecordsService.saveBatch(emsProductionRecords);
                if(!saveBatch){
                    throw new BusinessException(ErrorCode.SYSTEM_ERROR, "批量保存生产记录失败");
                }
            }
            // 为每条记录构建对应的生产记录
//              
            if (updateResult) {
                // TODO 发送PM完工邮件 完成
                sendPmCompleteEmail(workOrders, httpServletRequest);
                log.info("批量审批生产中工单成功，工单号: {}", workOrderNums);
                return ResultUtils.success(true);
            } else {
                log.error("批量审批生产中工单失败，工单号: {}", workOrderNums);
                throw new BusinessException(ErrorCode.SYSTEM_ERROR, "批量审批工单异常");
            }

        } catch (Exception e) {
            log.error("批量审批生产中工单异常，参数: {}", request, e);
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "批量审批工单异常");
        }
    }

    /**
     * 处理改造品和成品信息 - 优化版本
     */
    private void processModificationAndFinishedProducts(List<String> workOrderNums, List<EmsWorkOrder> workOrders) {
        // 1. 批量查询改造品详情
        LambdaQueryWrapper<EmsWorkOrderDetail> emsWorkOrderDetailLambdaQueryWrapper = new LambdaQueryWrapper<>();
        emsWorkOrderDetailLambdaQueryWrapper.eq(EmsWorkOrderDetail::getModelCategory, "D")
                .in(EmsWorkOrderDetail::getWorkOrderNumber, workOrderNums);
        List<EmsWorkOrderDetail> emsWorkOrderDetails = emsWorkOrderDetailService.list(emsWorkOrderDetailLambdaQueryWrapper);

        // 2. 批量预查询所有需要的数据以减少数据库调用
        Map<String, ChangeMachineBO> changeMachineBOMap = batchQueryChangeMachineBO(workOrderNums);
        Map<String, OldMachineMessageBO> oldMachineMessageBOMap = batchQueryOldMachineMessage(workOrderNums);
        Map<String, List<OldModificationBO>> oldModificationBOMap = batchQueryOldModification(workOrderNums);

        // 3. 计算需要的固定编号总数
        // 改造品总数：每个改造品详情的totalNum之和
        int modificationFixedNoCount = emsWorkOrderDetails.stream()
                .mapToInt(detail -> detail.getTotalNum() != null ? detail.getTotalNum() : 1)
                .sum();
        
        // 成品总数：每个工单的生产数量之和
        int finishedProductFixedNoCount = workOrders.stream()
                .mapToInt(workOrder -> workOrder.getProductionQuantity() != null ? workOrder.getProductionQuantity() : 1)
                .sum();
        
        int totalFixedNoCount = modificationFixedNoCount + finishedProductFixedNoCount;
        log.info("计算固定编号需求，改造品: {} 个，成品: {} 个，总计: {} 个", 
                modificationFixedNoCount, finishedProductFixedNoCount, totalFixedNoCount);

        // 4. 批量生成固定编号
        List<String> allFixedNos = batchGenerateFixedNos(totalFixedNoCount);
        
        // 5. 处理改造品
        if (!emsWorkOrderDetails.isEmpty()) {
            processModificationProducts(emsWorkOrderDetails, changeMachineBOMap, 
                    allFixedNos.subList(0, modificationFixedNoCount));
        }

        // 6. 处理成品信息
        List<String> finishedProductFixedNos = allFixedNos.subList(modificationFixedNoCount, allFixedNos.size());
        processFinishedProductsParallel(workOrders, changeMachineBOMap, oldMachineMessageBOMap, 
                                      oldModificationBOMap, finishedProductFixedNos);
    }

    /**
     * 批量查询 ChangeMachineBO
     */
    private Map<String, ChangeMachineBO> batchQueryChangeMachineBO(List<String> workOrderNums) {
        Map<String, ChangeMachineBO> result = new HashMap<>();
        // 这里假设 mapper 支持批量查询，如果不支持需要优化 SQL
        for (String workOrderNum : workOrderNums) {
            ChangeMachineBO changeMachineBO = this.baseMapper.getFinishedProductModel(workOrderNum);
            result.put(workOrderNum, changeMachineBO);
        }
        return result;
    }

    /**
     * 批量查询 OldMachineMessageBO
     */
    private Map<String, OldMachineMessageBO> batchQueryOldMachineMessage(List<String> workOrderNums) {
        Map<String, OldMachineMessageBO> result = new HashMap<>();
        for (String workOrderNum : workOrderNums) {
            OldMachineMessageBO oldMachineMessageBO = this.baseMapper.getOldMachineMessage(workOrderNum);
            result.put(workOrderNum, oldMachineMessageBO);
        }
        return result;
    }

    /**
     * 批量查询 OldModificationBO
     */
    private Map<String, List<OldModificationBO>> batchQueryOldModification(List<String> workOrderNums) {
        Map<String, List<OldModificationBO>> result = new HashMap<>();
        for (String workOrderNum : workOrderNums) {
            List<OldModificationBO> oldFixedNos = this.baseMapper.getOldModification(workOrderNum);
            result.put(workOrderNum, oldFixedNos);
        }
        return result;
    }

    /**
     * 批量生成固定编号 - 优化版本
     * 先获取一个起始编号，然后按规则递增生成后续编号
     */
    private synchronized List<String> batchGenerateFixedNos(int count) {
        List<String> fixedNos = new ArrayList<>();
        
        log.info("开始批量生成 {} 个固定编号", count);
        
        try {
            // 获取起始编号（数据库中当前最大编号的下一个）
            String startFixedNo = emsMainEngineMapper.getFixedNo();
            if (startFixedNo == null || startFixedNo.trim().isEmpty()) {
                throw new BusinessException(ErrorCode.SYSTEM_ERROR, "无法从数据库获取起始固定编号");
            }
            
            log.info("获取起始固定编号: {}", startFixedNo);
            
            // 解析起始编号
            if (startFixedNo.length() != 7) {
                throw new BusinessException(ErrorCode.SYSTEM_ERROR, "起始固定编号格式不正确: " + startFixedNo);
            }
            
            String yearMonth = startFixedNo.substring(0, 4); // 年月部分 (YYMM)
            int startSequence = Integer.parseInt(startFixedNo.substring(4, 7)); // 序号部分
            
            // 检查是否有足够的编号空间
            if (startSequence + count - 1 > 999) {
                throw new BusinessException(ErrorCode.SYSTEM_ERROR, 
                    String.format("当前年月(%s)剩余编号不足，起始序号: %d, 需要数量: %d", yearMonth, startSequence, count));
            }
            
            // 生成连续的固定编号
            for (int i = 0; i < count; i++) {
                int currentSequence = startSequence + i;
                String fixedNo = yearMonth + String.format("%03d", currentSequence);
                fixedNos.add(fixedNo);
                log.debug("生成固定编号: {} (第{}/{}个)", fixedNo, i + 1, count);
            }
            
            log.info("成功批量生成 {} 个连续固定编号，范围: {} ~ {}", 
                    count, fixedNos.get(0), fixedNos.get(fixedNos.size() - 1));
            
        } catch (Exception e) {
            log.error("批量生成固定编号失败", e);
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "批量生成固定编号失败: " + e.getMessage());
        }
        
        return fixedNos;
    }
    
    

    /**
     * 处理改造品
     */
    private void processModificationProducts(List<EmsWorkOrderDetail> emsWorkOrderDetails, 
                                           Map<String, ChangeMachineBO> changeMachineBOMap,
                                           List<String> modificationFixedNos) {
        
//        // 性能优化：批量查询改造品的成品信息
//        Set<String> modificationWorkOrderNums = emsWorkOrderDetails.stream()
//                .map(EmsWorkOrderDetail::getWorkOrderNumber)
//                .collect(Collectors.toSet());

        // 往ems_main_engine中插入数据
        List<EmsMainEngine> emsMainEngines = new ArrayList<>();

        
        int fixedNoIndex = 0; // 用于跟踪固定编号的索引
        
        for (EmsWorkOrderDetail emsWorkOrderDetail : emsWorkOrderDetails) {
            ChangeMachineBO changeMachineBO = changeMachineBOMap.get(emsWorkOrderDetail.getWorkOrderNumber());
//            获取改造品同类型的基础数据
            OldMachineMessageBO oldMachineMessageBO = emsMainEngineService.getSameMessage(emsWorkOrderDetail.getModelType());
            // 获取总数量，如果为null则默认为1
            Integer totalNum = emsWorkOrderDetail.getTotalNum() != null ? emsWorkOrderDetail.getTotalNum() : 1;
            log.info("处理改造品，工单号: {}, 型号: {}, 总数量: {}", 
                    emsWorkOrderDetail.getWorkOrderNumber(), 
                    emsWorkOrderDetail.getModelName(), 
                    totalNum);
            
            // 根据总数量插入多条记录，每条记录数量为1
            for (int j = 0; j < totalNum; j++) {
                EmsMainEngine emsMainEngine = new EmsMainEngine();
                emsMainEngine.setFixedNo(modificationFixedNos.get(fixedNoIndex++));
                emsMainEngine.setModelName(emsWorkOrderDetail.getModelName());
                emsMainEngine.setType(emsWorkOrderDetail.getModelType());
                emsMainEngine.setModelStatus(ModelStatusEnum.MODIFICATION_BEFORE_EDIT.getValue());
                emsMainEngine.setCanWorkOrder(2);
                emsMainEngine.setWorkOrderNumber(emsWorkOrderDetail.getWorkOrderNumber());
                emsMainEngine.setTotalNum(1); // 每条记录数量为1
                emsMainEngine.setInventoryNum(1); // 每条记录库存为1
                emsMainEngine.setUsedNum(0);
                emsMainEngine.setScrapNum(0);
                emsMainEngine.setInstoreOperator(changeMachineBO.getUserId());
                emsMainEngine.setInsertTime(LocalDateTime.now());
                emsMainEngine.setInstoreDate(LocalDateTime.now());
                emsMainEngine.setUpdateTime(LocalDateTime.now());
                emsMainEngine.setFinishedProductModel(changeMachineBO.getFinishedProductModel());
                emsMainEngines.add(emsMainEngine);
                if (oldMachineMessageBO != null) {
                    emsMainEngine.setCategory(oldMachineMessageBO.getCategory());
                    emsMainEngine.setCpu(oldMachineMessageBO.getCpu());
                    emsMainEngine.setHdd(oldMachineMessageBO.getHdd());
                    emsMainEngine.setMemory(oldMachineMessageBO.getMemory());
                    emsMainEngine.setType(oldMachineMessageBO.getType());
                    emsMainEngine.setScreenSize(oldMachineMessageBO.getScreenSize());
                    emsMainEngine.setCdRom(oldMachineMessageBO.getCdRom());
                    emsMainEngine.setDepartment(oldMachineMessageBO.getDepartment());
                    emsMainEngine.setSectionManager(oldMachineMessageBO.getSectionManager());
                    emsMainEngine.setBigCategory(oldMachineMessageBO.getBigCategory());
                    emsMainEngine.setCanBorrow(oldMachineMessageBO.getCanBorrow());
                    emsMainEngine.setMotherboard(oldMachineMessageBO.getMotherboard());
                    emsMainEngine.setUnitPrice(oldMachineMessageBO.getUnitPrice());
                }

            }
        }
        
//        boolean saveBatchRecord = emsProductionRecordsService.saveBatch(emsProductionRecords);
        boolean insertResult = emsMainEngineService.saveBatch(emsMainEngines);
        if (!insertResult ) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "批量插入改造品失败");
        }
        log.info("成功批量插入 {} 条改造品记录，{} 条生产记录", emsMainEngines.size());
    }

    /**
     * 串行处理成品信息 - 事务安全版本
     */
    private void processFinishedProductsParallel(List<EmsWorkOrder> workOrders,
                                               Map<String, ChangeMachineBO> changeMachineBOMap,
                                               Map<String, OldMachineMessageBO> oldMachineMessageBOMap,
                                               Map<String, List<OldModificationBO>> oldModificationBOMap,
                                               List<String> fixedNos) {
        
        // 使用普通集合，因为现在是串行处理
        List<EmsMainEngine> allFinishedProducts = new ArrayList<>();
//        List<EmsProductionRecords> emsAllFinishedProductionRecords = new ArrayList<>();

        // 串行处理每个工单
        int fixedNoIndex = 0; // 用于跟踪固定编号的索引
        
        for (EmsWorkOrder item : workOrders) {
            String workOrderNum = item.getWorkOrderNum();
            
            ChangeMachineBO changeMachineBO = changeMachineBOMap.get(workOrderNum);
            OldMachineMessageBO oldMachineMessageBO = oldMachineMessageBOMap.get(workOrderNum);
            List<OldModificationBO> oldFixedNos = oldModificationBOMap.get(workOrderNum);

            // 处理旧借用申请删除
            if (oldFixedNos != null && !oldFixedNos.isEmpty()) {
                Set<String> deleteMyBorrowRequest = oldFixedNos.stream()
                        .map(OldModificationBO::getEmsRequestId)
                        .collect(Collectors.toSet());
                boolean removeBatchByIds = emsMyBorrowService.removeBatchByIds(deleteMyBorrowRequest);
                if (!removeBatchByIds) {
                    throw new BusinessException(ErrorCode.SYSTEM_ERROR, 
                        "删除旧借用申请失败，工单号: " + workOrderNum);
                }
                
                // 更新样品状态
                for (OldModificationBO oldFixedNo : oldFixedNos) {
                    try {
                        sampleStatusUtils.updateSampleQuantityAndStatus(
                                Integer.valueOf(oldFixedNo.getBorrowNum()), 
                                oldFixedNo.getFixedNo(), 4, 3,workOrderNum);
                    } catch (Exception e) {
                        throw new BusinessException(ErrorCode.SYSTEM_ERROR, 
                            "更新样品状态失败，固定编号: " + oldFixedNo.getFixedNo() + ", 错误: " + e.getMessage());
                    }
                }
            }

            if (changeMachineBO == null) {
                throw new BusinessException(ErrorCode.SYSTEM_ERROR, 
                    "获取工单机器信息失败，工单号: " + workOrderNum);
            }

            // 获取生产数量，如果为null则默认为1
            Integer productionQuantity = item.getProductionQuantity() != null ? item.getProductionQuantity() : 1;
            log.info("处理成品，工单号: {}, 型号: {}, 生产数量: {}", 
                    workOrderNum, 
                    changeMachineBO.getMachineName(), 
                    productionQuantity);

            // 根据生产数量插入多条记录，每条记录数量为1
            for (int j = 0; j < productionQuantity; j++) {
                // 构建成品信息
                EmsMainEngine emsMainEngine = new EmsMainEngine();
                if (oldMachineMessageBO != null) {
                    emsMainEngine.setCategory(oldMachineMessageBO.getCategory());
                    emsMainEngine.setCpu(oldMachineMessageBO.getCpu());
                    emsMainEngine.setHdd(oldMachineMessageBO.getHdd());
                    emsMainEngine.setMemory(oldMachineMessageBO.getMemory());
                    emsMainEngine.setType(oldMachineMessageBO.getType());
                    emsMainEngine.setScreenSize(oldMachineMessageBO.getScreenSize());
                    emsMainEngine.setCdRom(oldMachineMessageBO.getCdRom());
                    emsMainEngine.setDepartment(oldMachineMessageBO.getDepartment());
                    emsMainEngine.setSectionManager(oldMachineMessageBO.getSectionManager());
                    emsMainEngine.setBigCategory(oldMachineMessageBO.getBigCategory());
                    emsMainEngine.setCanBorrow(oldMachineMessageBO.getCanBorrow());
                    emsMainEngine.setMotherboard(oldMachineMessageBO.getMotherboard());
                    emsMainEngine.setUnitPrice(oldMachineMessageBO.getUnitPrice());

                }
                
                emsMainEngine.setFixedNo(fixedNos.get(fixedNoIndex++));
                emsMainEngine.setModelName(changeMachineBO.getMachineName());
                emsMainEngine.setModelStatus(ModelStatusEnum.MODIFICATION_BEFORE_EDIT.getValue());
                emsMainEngine.setWorkOrderNumber(item.getWorkOrderNum());
                emsMainEngine.setTotalNum(1); // 每条记录数量为1
                emsMainEngine.setInventoryNum(1); // 每条记录库存为1
                emsMainEngine.setUsedNum(0);
                emsMainEngine.setScrapNum(0);
                emsMainEngine.setInstoreOperator(changeMachineBO.getUserId());
                emsMainEngine.setInsertTime(LocalDateTime.now());
                emsMainEngine.setInstoreDate(LocalDateTime.now());
                emsMainEngine.setUpdateTime(LocalDateTime.now());
                emsMainEngine.setFinishedProductModel(changeMachineBO.getFinishedProductModel());
                emsMainEngine.setType(changeMachineBO.getFinishedProductModel());
                emsMainEngine.setCanWorkOrder(1);
                allFinishedProducts.add(emsMainEngine);

//                // 为每条记录构建对应的生产记录
//                EmsProductionRecords emsProductionRecord = new EmsProductionRecords();
//                emsProductionRecord.setWorkOrderNum(item.getWorkOrderNum());
//                emsProductionRecord.setFinishedProductModel(changeMachineBO.getFinishedProductModel());
//                emsProductionRecord.setFinishedProductNumber(1); // 每条记录数量为1
//                emsProductionRecord.setCreateUserName(changeMachineBO.getUserName());
//                emsProductionRecord.setFixedNo(fixedNos.get(fixedNoIndex - 1));
//                emsProductionRecord.setConsumerNumber(1); // 每条记录数量为1
//                emsAllFinishedProductionRecords.add(emsProductionRecord);
            }

            log.debug("处理工单成功: {}, 生成记录数: {}", workOrderNum, productionQuantity);
        }

        // 批量插入所有成品信息
        if (!allFinishedProducts.isEmpty()) {
            try {
            boolean insertResult = emsMainEngineService.saveBatch(allFinishedProducts);
            if (!insertResult) {
                throw new BusinessException(ErrorCode.SYSTEM_ERROR, "批量插入成品失败");
            }
            log.info("成功批量插入 {} 条成品记录", allFinishedProducts.size());
            } catch (Exception e) {
                log.error("批量插入成品记录失败", e);
                throw new BusinessException(ErrorCode.SYSTEM_ERROR, "批量插入成品记录失败: " + e.getMessage());
            }
        }

        // 批量插入生产记录
//        if (!emsAllFinishedProductionRecords.isEmpty()) {
//            try {
//            boolean saveBatchRecord = emsProductionRecordsService.saveBatch(emsAllFinishedProductionRecords);
//            if (!saveBatchRecord) {
//                throw new BusinessException(ErrorCode.SYSTEM_ERROR, "批量插入生产记录失败");
//            }
//            log.info("成功批量插入 {} 条成品生产记录", emsAllFinishedProductionRecords.size());
//            } catch (Exception e) {
//                log.error("批量插入生产记录失败", e);
//                throw new BusinessException(ErrorCode.SYSTEM_ERROR, "批量插入生产记录失败: " + e.getMessage());
//            }
//        }
    }

    @Override
    public BaseResponse<String> getWorkOrderNumber() {
        try {
            // 从数据库获取工单号
            String dbWorkOrderNo = this.baseMapper.getWORKORDERNO();
            
            if (dbWorkOrderNo == null || dbWorkOrderNo.length() < 9) {
                return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "数据库返回的工单号格式不正确");
            }
            
            // 构建Redis key，使用完整的工单号作为key
            String redisKey = RedisKeyEnum.WORKER_ORDER_NEW_PREFIX.getValue() + dbWorkOrderNo;

            
            // 检查Redis中是否存在该工单号
            if (redisTemplate.hasKey(redisKey)) {
                LambdaUpdateWrapper<EmsEngineWorkOrder> emsEngineWorkOrderLambdaUpdateWrapper=new LambdaUpdateWrapper<EmsEngineWorkOrder>();
                emsEngineWorkOrderLambdaUpdateWrapper
                        .eq(EmsEngineWorkOrder::getWorkOrderNumber,dbWorkOrderNo)
                        .set(EmsEngineWorkOrder::getIsDelete,1);
                emsEngineWorkOrderService.remove(emsEngineWorkOrderLambdaUpdateWrapper);
                LambdaUpdateWrapper<EmsWorkOrderDetail> emsWorkOrderDetailLambdaUpdateWrapper=new LambdaUpdateWrapper<EmsWorkOrderDetail>();
                emsWorkOrderDetailLambdaUpdateWrapper
                        .eq(EmsWorkOrderDetail::getWorkOrderNumber,dbWorkOrderNo)
                        .set(EmsWorkOrderDetail::getIsDelete,1);
                emsWorkOrderDetailService.remove(emsWorkOrderDetailLambdaUpdateWrapper);
            }
            String newRedisKey = RedisKeyEnum.WORKER_ORDER_NEW_PREFIX.getValue() + dbWorkOrderNo;
            redisTemplate.opsForValue().set(newRedisKey, "1");
            return ResultUtils.success(dbWorkOrderNo);
        } catch (Exception e) {
            log.error("获取工单号异常", e);
            return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "获取工单号失败: " + e.getMessage());
        }
    }
    
    @Override
    public BaseResponse<WorkOrderByBomNumVO> getWorkOrdersByBomNum(WorkOrderByBomNumRequest request) {
        log.info("根据BOM号查询关联工单信息，参数: {}", request);
        
        try {
            // 1. 根据BOM号查询关联的工单号列表
            List<String> workOrderList = this.baseMapper.getWorkOrderNumsByBomNum(request.getBomId());
            if (CollUtil.isNotEmpty(workOrderList)) { // Hutool 安全集合判断
                String firstWorkOrderNum = workOrderList.get(0);
                if (StrUtil.isBlank(request.getWorkOrderNum())) {
                    request.setWorkOrderNum(firstWorkOrderNum);
                }
            }
            // 2. 分页查询BOM详情信息
            Page<WorkOrderByBomNumVO.BomDetailItem> page = new Page<>(request.getCurrent(), request.getPageSize());
            Page<WorkOrderByBomNumVO.BomDetailItem> bomDetailPage = this.baseMapper.pageBomDetailByBomNum(page, request);
            
            // 3. 构建响应对象
            WorkOrderByBomNumVO result = new WorkOrderByBomNumVO();
            result.setWorkOrderList(workOrderList);
            result.setBomDetailPage(bomDetailPage);
            
            log.info("根据BOM号查询关联工单信息成功，BOM号: {}, 工单数量: {}, BOM详情数量: {}", 
                    request.getBomId(), workOrderList.size(), bomDetailPage.getRecords().size());
            
            return ResultUtils.success(result);
            
        } catch (Exception e) {
            log.error("根据BOM号查询关联工单信息异常，参数: {}", request, e);
            return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "查询失败: " + e.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public BaseResponse<Boolean> batchAcceptanceWorkOrders(WorkOrderBatchAcceptanceRequest request, HttpServletRequest httpServletRequest) {
        log.info("批量验收待验收工单，参数: {}", request);

        try {
            List<String> workOrderNums = request.getWorkOrderNums();

            // 1. 参数验证
            if (workOrderNums == null || workOrderNums.isEmpty()) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "工单号列表不能为空");
            }

            // 2. 查询所有工单的当前状态
            LambdaQueryWrapper<EmsWorkOrder> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.in(EmsWorkOrder::getWorkOrderNum, workOrderNums)
                    .eq(EmsWorkOrder::getIsDelete, 0);
            List<EmsWorkOrder> workOrders = this.list(queryWrapper);

            if (workOrders.size() != workOrderNums.size()) {
                return ResultUtils.error(ErrorCode.PARAMS_ERROR, "部分工单不存在或已删除");
            }

            // 3. 检查所有工单状态是否都是待验收(状态值为4)
            List<EmsWorkOrder> nonAcceptanceOrders = workOrders.stream()
                    .filter(order -> !WorkOrderStatusEnum.ACCEPT.getValue().equals(order.getWorkOrderStatus()))
                    .collect(Collectors.toList());

            if (!nonAcceptanceOrders.isEmpty()) {
                List<String> nonAcceptanceNums = nonAcceptanceOrders.stream()
                        .map(EmsWorkOrder::getWorkOrderNum)
                        .collect(Collectors.toList());
                return ResultUtils.error(ErrorCode.PARAMS_ERROR,
                        "有工单状态为非待验收状态，工单号: " + String.join(", ", nonAcceptanceNums));
            }

//            // 4. 检查工单下的样品状态是否都是在库状态
//            List<String> invalidWorkOrderNums = new ArrayList<>();
//
//            for (String workOrderNum : workOrderNums) {
//                // 查询该工单下的所有样品
//                LambdaQueryWrapper<EmsMainEngine> engineQueryWrapper = new LambdaQueryWrapper<>();
//                engineQueryWrapper.eq(EmsMainEngine::getWorkOrderNumber, workOrderNum);
//                List<EmsMainEngine> engines = emsMainEngineService.list(engineQueryWrapper);
//
//            }

            // 6. 批量更新工单状态为已完工(状态值为5)
            LambdaUpdateWrapper<EmsWorkOrder> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.in(EmsWorkOrder::getWorkOrderNum, workOrderNums)
                    .eq(EmsWorkOrder::getIsDelete, 0)
                    .set(EmsWorkOrder::getWorkOrderStatus, WorkOrderStatusEnum.COMPLETED.getValue())
                    .set(EmsWorkOrder::getUpdateTime, LocalDateTime.now());

            boolean updateResult = this.update(updateWrapper);

            if (updateResult) {
                // TODO 发送样品管理员验收完成邮件
                sendSampleAcceptanceEmail(workOrders, httpServletRequest);
                
                log.info("批量验收工单成功，工单号: {}", workOrderNums);
                return ResultUtils.success(true);
            } else {
                log.error("批量验收工单失败，工单号: {}", workOrderNums);
                return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "批量验收工单失败");
            }

        } catch (BusinessException e) {
            log.error("批量验收工单失败: {}", e.getMessage());
            throw e;
        } catch (Exception e) {
            log.error("批量验收工单异常，参数: {}", request, e);
            return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "批量验收工单异常: " + e.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public BaseResponse<Boolean> batchDeleteWorkOrders(WorkOrderBatchDeleteRequest request) {
        log.info("批量删除工单，参数: {}", request);

        try {
            List<String> workOrderNums = request.getWorkOrderNums();

            // 1. 参数验证
            if (workOrderNums == null || workOrderNums.isEmpty()) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "工单号列表不能为空");
            }

            // 2. 查询所有工单的当前状态
            LambdaQueryWrapper<EmsWorkOrder> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.in(EmsWorkOrder::getWorkOrderNum, workOrderNums)
                    .eq(EmsWorkOrder::getIsDelete, 0);
            List<EmsWorkOrder> workOrders = this.list(queryWrapper);

            if (workOrders.size() != workOrderNums.size()) {
                return ResultUtils.error(ErrorCode.PARAMS_ERROR, "部分工单不存在或已删除");
            }

            // 3. 检查工单状态，只能删除待生产审批(0)和待修改(1)状态的工单
            List<EmsWorkOrder> invalidWorkOrders = workOrders.stream()
                    .filter(workOrder -> !WorkOrderStatusEnum.PENDING.getValue().equals(workOrder.getWorkOrderStatus()) 
                            && !WorkOrderStatusEnum.MODIFIED.getValue().equals(workOrder.getWorkOrderStatus()))
                    .collect(Collectors.toList());

            if (!invalidWorkOrders.isEmpty()) {
                List<String> invalidWorkOrderNums = invalidWorkOrders.stream()
                        .map(EmsWorkOrder::getWorkOrderNum)
                        .collect(Collectors.toList());
                return ResultUtils.error(ErrorCode.PARAMS_ERROR,
                        "只能删除待生产审批和待修改状态的工单，无效工单号: " + String.join(", ", invalidWorkOrderNums));
            }

            // 4. 开始批量删除相关数据
            int deletedRecords = 0;

            // 4.1 删除 ems_engine_work_order 表中的关联数据
            LambdaQueryWrapper<EmsEngineWorkOrder> engineWorkOrderWrapper = new LambdaQueryWrapper<>();
            engineWorkOrderWrapper.in(EmsEngineWorkOrder::getWorkOrderNumber, workOrderNums);
            List<EmsEngineWorkOrder> engineWorkOrders = emsEngineWorkOrderService.list(engineWorkOrderWrapper);
            if (!engineWorkOrders.isEmpty()) {
                boolean deleteEngineWorkOrderResult = emsEngineWorkOrderService.remove(engineWorkOrderWrapper);
                if (deleteEngineWorkOrderResult) {
                    deletedRecords += engineWorkOrders.size();
                    log.info("成功删除 {} 条 ems_engine_work_order 记录", engineWorkOrders.size());
                }
            }

            // 4.2 查询要删除的 ems_work_order_detail 记录，获取其ID用于删除关联的 ems_bom_contact
            LambdaQueryWrapper<EmsWorkOrderDetail> workOrderDetailWrapper = new LambdaQueryWrapper<>();
            workOrderDetailWrapper.in(EmsWorkOrderDetail::getWorkOrderNumber, workOrderNums);
            List<EmsWorkOrderDetail> workOrderDetails = emsWorkOrderDetailService.list(workOrderDetailWrapper);
            
            // 4.3 根据 ems_work_order_detail 的 ID 删除 ems_bom_contact 表中的关联数据
            if (!workOrderDetails.isEmpty()) {
                List<Long> bomDetailIds = workOrderDetails.stream()
                        .map(EmsWorkOrderDetail::getId)
                        .collect(Collectors.toList());
                
                LambdaQueryWrapper<EmsBomContact> bomContactWrapper = new LambdaQueryWrapper<>();
                bomContactWrapper.in(EmsBomContact::getBomDetailId, bomDetailIds);
                List<EmsBomContact> bomContacts = emsBomContactService.list(bomContactWrapper);
                if (!bomContacts.isEmpty()) {
                    boolean deleteBomContactResult = emsBomContactService.remove(bomContactWrapper);
                    if (deleteBomContactResult) {
                        deletedRecords += bomContacts.size();
                        log.info("成功删除 {} 条 ems_bom_contact 记录", bomContacts.size());
                    }
                }
            }

            // 4.4 删除 ems_work_order_detail 表中的关联数据
            if (!workOrderDetails.isEmpty()) {
                boolean deleteWorkOrderDetailResult = emsWorkOrderDetailService.removeByIds(
                        workOrderDetails.stream()
                                .map(EmsWorkOrderDetail::getId)
                                .collect(Collectors.toList())
                );
                if (deleteWorkOrderDetailResult) {
                    deletedRecords += workOrderDetails.size();
                    log.info("成功删除 {} 条 ems_work_order_detail 记录", workOrderDetails.size());
                }
            }

            // 4.5 最后删除 ems_work_order 表中的工单数据
            boolean deleteWorkOrderResult = this.removeByIds(workOrderNums);

            if (deleteWorkOrderResult) {
                deletedRecords += workOrders.size();
                log.info("成功删除 {} 条 ems_work_order 记录", workOrders.size());
                log.info("批量删除工单成功，工单号: {}，总共删除 {} 条相关记录", workOrderNums, deletedRecords);
                return ResultUtils.success(true);
            } else {
                log.error("删除工单失败，工单号: {}", workOrderNums);
                return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "删除工单失败");
            }

        } catch (BusinessException e) {
            log.error("批量删除工单失败: {}", e.getMessage());
            throw e;
        } catch (Exception e) {
            log.error("批量删除工单异常，参数: {}", request, e);
            return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "批量删除工单异常: " + e.getMessage());
        }
    }
    
    /**
     * 发送批量拒绝工单邮件
     */
    private void sendBatchRejectEmail(List<EmsWorkOrder> workOrders, String rejectReason, HttpServletRequest httpServletRequest,List<String> workOrderIds) {
        try {
            // 获取用户信息
            UserLoginVO userLoginVO = (UserLoginVO) httpServletRequest.getSession().getAttribute("user_login");
            if (userLoginVO == null) {
                log.warn("用户未登录，无法发送拒绝邮件");
                return;
            }
            List<WorkOrderMailVO> workOrderMailVO= this.baseMapper.getWorkOrderListByIds(workOrderIds);
            // 准备邮件表格数据
            List<HashMap<String, String>> tableDatas = new ArrayList<>();
            Set<String> toEmails = new HashSet<>();
            for (WorkOrderMailVO workOrder : workOrderMailVO) {
                HashMap<String, String> tableDataMap = new HashMap<>();
                tableDataMap.put("workOrderNum", workOrder.getWorkOrderNum());
                tableDataMap.put("name", workOrder.getUserName());
                tableDataMap.put("bomNum", workOrder.getBomNum());
                tableDataMap.put("bomVersion", workOrder.getVersion());
                tableDataMap.put("reason", rejectReason != null ? rejectReason : "无");
                toEmails.add(workOrder.getEmail());
                tableDatas.add(tableDataMap);
            }
//            TODO 课长拒绝工单审批邮件
            // 创建邮件队列
            EmsMailQueue emsMailQueue = new EmsMailQueue();
            emsMailQueue.setType(MailEnum.WORK_ORDER_BATCH_REJECT.getValue());
            emsMailQueue.setMainBody(mailTemplate.getWorkOrderBatchReject());
            emsMailQueue.setSubject(MailTemplate.SUBJECT_WORK_ORDER_BATCH_REJECT + " "+  userLoginVO.getSectionName() + " " + userLoginVO.getUserName());
            emsMailQueue.setFrom(userLoginVO.getEmail());
            // 获取收件人列表 - 发送给申请人
            if (toEmails.isEmpty()) {
                log.warn("没有找到有效的收件人邮箱，无法发送拒绝邮件");
                return;
            }

            emsMailQueue.setTo(JSONUtil.toJsonStr(toEmails));
            emsMailQueue.setTableData(JSONUtil.toJsonStr(tableDatas));
            boolean saveMail = emsMailQueueService.save(emsMailQueue);
            if (saveMail) {
                log.info("成功保存批量拒绝工单邮件，工单数量: {}, 收件人数量: {}", workOrders.size(), toEmails.size());
            } else {
                log.error("保存批量拒绝工单邮件失败");
            }
            
        } catch (Exception e) {
            log.error("发送批量拒绝工单邮件失败", e);
            // 邮件发送失败不影响主流程，只记录日志
        }
    }
    
    /**
     * 发送批量同意工单邮件
     */
    private void sendBatchApproveEmail(List<EmsWorkOrder> workOrders, HttpServletRequest httpServletRequest,List<String> workOrderIds) {
        try {
            // 获取用户信息
            UserLoginVO userLoginVO = (UserLoginVO) httpServletRequest.getSession().getAttribute("user_login");
            if (userLoginVO == null) {
                log.warn("用户未登录，无法发送同意邮件");
                return;
            }
            List<WorkOrderMailVO> workOrderMailVO= this.baseMapper.getWorkOrderListByIds(workOrderIds);
            
            // 准备邮件表格数据
            List<String> toEmails = usersService.getSampleMail(14);
            List<HashMap<String, String>> tableDatas = new ArrayList<>();
            for (WorkOrderMailVO workOrder : workOrderMailVO) {
                HashMap<String, String> tableDataMap = new HashMap<>();
                tableDataMap.put("workOrderNum", workOrder.getWorkOrderNum());
                tableDataMap.put("name", workOrder.getUserName());
                tableDataMap.put("bomNum", workOrder.getBomNum());
                tableDataMap.put("bomVersion", workOrder.getVersion());
                tableDatas.add(tableDataMap);
            }
//            TODO 课长同意工单审批邮件
            // 创建邮件队列
            EmsMailQueue emsMailQueue = new EmsMailQueue();
            emsMailQueue.setType(MailEnum.WORK_ORDER_BATCH_APPROVE.getValue());
            emsMailQueue.setMainBody(mailTemplate.getWorkOrderBatchApprove());
            emsMailQueue.setSubject(MailTemplate.SUBJECT_WORK_ORDER_BATCH_APPROVE +" "+ userLoginVO.getSectionName() +" "+ userLoginVO.getUserName());
            emsMailQueue.setFrom(userLoginVO.getEmail());
            if (toEmails.isEmpty()) {
                log.warn("没有找到有效的收件人邮箱，无法发送同意邮件");
                return;
            }
            emsMailQueue.setTo(new ArrayList<>(toEmails).toString());
            emsMailQueue.setTableData(JSONUtil.toJsonStr(tableDatas));
            boolean saveMail = emsMailQueueService.save(emsMailQueue);
            if (saveMail) {
                log.info("成功保存批量同意工单邮件，工单数量: {}, 收件人数量: {}", workOrders.size(), toEmails.size());
            } else {
                log.error("保存批量同意工单邮件失败");
            }
            
        } catch (Exception e) {
            log.error("发送批量同意工单邮件失败", e);
            // 邮件发送失败不影响主流程，只记录日志
        }
    }
    
    /**
     * 发送PM完工邮件
     */
    private void sendPmCompleteEmail(List<EmsWorkOrder> workOrders, HttpServletRequest httpServletRequest) {
        try {
            if (workOrders == null || workOrders.isEmpty()) {
                log.warn("工单列表为空，无法发送PM完工邮件");
                return;
            }
            // 获取用户信息
            UserLoginVO userLoginVO = (UserLoginVO) httpServletRequest.getSession().getAttribute("user_login");
            if (userLoginVO == null) {
                log.warn("用户未登录，无法发送同意邮件");
                return;
            }
            // 获取工单号列表
            List<String> workOrderIds = workOrders.stream()
                    .map(EmsWorkOrder::getWorkOrderNum)
                    .map(String::valueOf)
                    .collect(Collectors.toList());
            
            // 查询工单邮件信息
            List<WorkOrderMailVO> workOrderMailVOs = this.baseMapper.getWorkOrderListByIds(workOrderIds);
            
            if (workOrderMailVOs.isEmpty()) {
                log.warn("未找到工单邮件信息，工单数量: {}", workOrders.size());
                return;
            }
            
            // 准备邮件表格数据
            List<HashMap<String, String>> tableDatas = new ArrayList<>();
            Set<String> toEmails = new HashSet<>();
            
            for (WorkOrderMailVO workOrderMailVO : workOrderMailVOs) {
                HashMap<String, String> tableDataMap = new HashMap<>();
                tableDataMap.put("workOrderNum", workOrderMailVO.getWorkOrderNum());
                tableDataMap.put("name", workOrderMailVO.getUserName());
                tableDataMap.put("bomNum", workOrderMailVO.getBomNum());
                tableDataMap.put("bomVersion", workOrderMailVO.getVersion());
                toEmails.add(workOrderMailVO.getEmail());
                tableDatas.add(tableDataMap);
            }
            List<String> sampleMail = usersService.getSampleMail(14);
            // 创建邮件队列
            EmsMailQueue emsMailQueue = new EmsMailQueue();
            emsMailQueue.setType(MailEnum.WORK_ORDER_PM_COMPLETE.getValue());
            emsMailQueue.setMainBody(mailTemplate.getWorkOrderPmComplete());
            emsMailQueue.setSubject(MailTemplate.SUBJECT_WORK_ORDER_PM_COMPLETE +" "+ userLoginVO.getSectionName()+" "+userLoginVO.getUserName());
            emsMailQueue.setFrom(userLoginVO.getEmail()); // 系统邮箱，可以根据需要调整
            emsMailQueue.setTo(sampleMail.toString());
            // 设置收件人
            if (toEmails.isEmpty()) {
                log.warn("没有找到有效的收件人邮箱，无法发送PM完工邮件");
                return;
            }
            emsMailQueue.setTableData(JSONUtil.toJsonStr(tableDatas));
            
            // 保存邮件到队列
            boolean saveMail = emsMailQueueService.save(emsMailQueue);
            if (saveMail) {
                log.info("成功保存PM完工邮件，工单数量: {}, 收件人数量: {}", workOrders.size(), toEmails.size());
            } else {
                log.error("保存PM完工邮件失败");
            }
            
                 } catch (Exception e) {
             log.error("发送PM完工邮件失败", e);
             // 邮件发送失败不影响主流程，只记录日志
         }
     }
     
     /**
      * 发送样品管理员验收完成邮件
      */
     private void sendSampleAcceptanceEmail(List<EmsWorkOrder> workOrders, HttpServletRequest httpServletRequest) {
         try {
             if (workOrders == null || workOrders.isEmpty()) {
                 log.warn("工单列表为空，无法发送样品管理员验收邮件");
                 return;
             }
             
             // 获取用户信息
             UserLoginVO userLoginVO = (UserLoginVO) httpServletRequest.getSession().getAttribute("user_login");
             if (userLoginVO == null) {
                 log.warn("用户未登录，无法发送样品管理员验收邮件");
                 return;
             }
             
             // 获取工单号列表
             List<String> workOrderIds = workOrders.stream()
                     .map(EmsWorkOrder::getWorkOrderNum)
                     .map(String::valueOf)
                     .collect(Collectors.toList());
             
             // 查询工单邮件信息
             List<WorkOrderMailVO> workOrderMailVOs = this.baseMapper.getWorkOrderListByIds(workOrderIds);
             
             if (workOrderMailVOs.isEmpty()) {
                 log.warn("未找到工单邮件信息，工单数量: {}", workOrders.size());
                 return;
             }
             
             // 准备邮件表格数据
             List<HashMap<String, String>> tableDatas = new ArrayList<>();
             Set<String> toEmails = new HashSet<>();
             
             for (WorkOrderMailVO workOrderMailVO : workOrderMailVOs) {
                 HashMap<String, String> tableDataMap = new HashMap<>();
                 tableDataMap.put("workOrderNum", workOrderMailVO.getWorkOrderNum());
                 tableDataMap.put("name", workOrderMailVO.getUserName());
                 tableDataMap.put("bomNum", workOrderMailVO.getBomNum());
                 tableDataMap.put("bomVersion", workOrderMailVO.getVersion());
                 toEmails.add(workOrderMailVO.getEmail());
                 tableDatas.add(tableDataMap);
             }
             
             // 创建邮件队列
             EmsMailQueue emsMailQueue = new EmsMailQueue();
             emsMailQueue.setType(MailEnum.WORK_ORDER_SAMPLE_ACCEPTANCE.getValue());
             emsMailQueue.setMainBody(mailTemplate.getWorkOrderSampleAcceptance());
             emsMailQueue.setSubject(MailTemplate.SUBJECT_WORK_ORDER_SAMPLE_ACCEPTANCE +" "+ userLoginVO.getSectionName()+" "+ userLoginVO.getUserName());
             emsMailQueue.setFrom(userLoginVO.getEmail());
             
             // 设置收件人 - 发送给工单申请人
             if (toEmails.isEmpty()) {
                 log.warn("没有找到有效的收件人邮箱，无法发送样品管理员验收邮件");
                 return;
             }
             
             emsMailQueue.setTo(new ArrayList<>(toEmails).toString());
             emsMailQueue.setTableData(JSONUtil.toJsonStr(tableDatas));
             
             // 保存邮件到队列
             boolean saveMail = emsMailQueueService.save(emsMailQueue);
             if (saveMail) {
                 log.info("成功保存样品管理员验收邮件，工单数量: {}, 收件人数量: {}", workOrders.size(), toEmails.size());
             } else {
                 log.error("保存样品管理员验收邮件失败");
             }
             
         } catch (Exception e) {
             log.error("发送样品管理员验收邮件失败", e);
             // 邮件发送失败不影响主流程，只记录日志
                 }
    }

    @Override
    public void exportWorkOrderData(WorkOrderExportRequest workOrderExportRequest, HttpServletResponse response) {
        try {
            log.info("开始导出工单数据，参数: {}", workOrderExportRequest);
            
            // 获取导出数据
            List<String> workOrderNums = null;
            if (workOrderExportRequest != null && workOrderExportRequest.getWorkOrderNums() != null && !workOrderExportRequest.getWorkOrderNums().isEmpty()) {
                workOrderNums = workOrderExportRequest.getWorkOrderNums();
            }
            
            // 查询导出数据
            List<WorkOrderExportVO> exportData = this.baseMapper.getWorkOrderExportData(workOrderNums);
            
            // 生成文件名加年月日时分秒
            String fileName = "工单数据" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss"));
            
            // 使用FastExcelUtils导出
            FastExcelUtils.exportExcelWithStyle(
                exportData, 
                WorkOrderExportVO.class, 
                fileName, 
                "工单数据", 
                response
            );
            
            log.info("工单数据导出完成，共导出 {} 条记录", exportData.size());
            
        } catch (Exception e) {
            log.error("导出工单数据失败", e);
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "导出工单数据失败: " + e.getMessage());
        }
    }
}




